package cn.xinfei.xdecision.engine.runner.context;

import cn.xinfei.xdecision.common.utils.util.JsonUtils;
import cn.xinfei.xdecision.constant.GlobalConstant;
import cn.xinfei.xdecision.engine.runner.datax.RiskDataApiAdapter;
import cn.xinfei.xdecision.engine.runner.executor.model.StateTransmitModel;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.support.spring.PropertyPreFilters;
import com.alibaba.ttl.TransmittableThreadLocal;
import com.baomidou.mybatisplus.core.MybatisMapperRegistry;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;

@Slf4j
@Data
public class XDecisionContext<T, K> implements ExclusionStrategy {


    private static String[] excludeProperties = {"iEngineRunnerNode"};
    private static PropertyPreFilters filters = new PropertyPreFilters();
    private static PropertyPreFilters.MySimplePropertyPreFilter excludefilter = filters.addFilter();

    static {
        excludefilter.addExcludes(excludeProperties);
    }

    private transient StateTransmitModel stateContext = StateTransmitModel.build();


    /**
     * 变量上下文
     * 声明为transient，单独序列化
     */
    private PipelineContext pipelineContext = new PipelineContext();

    /**
     * 决策流节点信息
     * 声明为transient，不序列化
     */
    private transient PipelineMetaInfoContext pipelineMetaInfoContext = new PipelineMetaInfoContext();



 /*   private final static ThreadLocal<XDecisionContext> threadLocal = new ThreadLocal<XDecisionContext>() {
        @Override
        protected XDecisionContext initialValue() {
            // 在ThreadLocal中放入一个初始值
            System.out.println("build XDecisionContext,currentThread="+ Thread.currentThread().getId());
            log.warn("build XDecisionContext,currentThread={}", Thread.currentThread().getId());
            return new XDecisionContext();
        }
    }; private final static InheritableThreadLocal<XDecisionContext> threadLocal = new InheritableThreadLocal<XDecisionContext>() {
        @Override
        protected XDecisionContext initialValue() {
            // 在ThreadLocal中放入一个初始值
            System.out.println("build XDecisionContext,currentThread="+ Thread.currentThread().getId());
            log.warn("build XDecisionContext,currentThread={}", Thread.currentThread().getId());
            return new XDecisionContext();
        }
    };*/

    private transient static TransmittableThreadLocal<XDecisionContext> threadLocal = new TransmittableThreadLocal<XDecisionContext>() {
        @Override
        protected XDecisionContext initialValue() {
            // 在ThreadLocal中放入一个初始值
//            log.warn("build XDecisionContext,currentThread={}", Thread.currentThread().getId());
            return new XDecisionContext();
        }
    };

    private XDecisionContext() {
    }


    public static XDecisionContext getContext() {
        return threadLocal.get();
    }

    public static PipelineContext setContext(String context) {
        Gson gson = new GsonBuilder()
                .create();
        PipelineContext newPipelineContext = gson.fromJson(context, PipelineContext.class);
//        PipelineContext newPipelineContext = JSONObject.toJavaObject(JSONObject.parseObject(context), PipelineContext.class);
        getContext().setPipelineContext(newPipelineContext);
        MDC.put(GlobalConstant.TRACE_ID, PipelineContextHolder.getRequestId());
        MDC.put(GlobalConstant.PID, PipelineContextHolder.getDecisionId());
        return newPipelineContext;
    }

    public static void setContext(XDecisionContext context) {
        threadLocal.set(context);
    }

    public String toJson() {
        String s = JsonUtils.toJsonString(this);
        return s;
    }


    public static void destroy() {
        PipelineContextHolder.clear();
        getContext().getPipelineMetaInfoContext().clear();
//        getContext().getFieldMap().clear();
        threadLocal.remove();
//        log.warn("remove XDecisionContext,currentThread={}", Thread.currentThread().getId());
    }

    public String getTpCode() {
        if (StringUtils.isEmpty(PipelineContextHolder.getTpCode())) {
            return "DEFAULT";
        }
        return PipelineContextHolder.getTpCode();
    }


    public XDecisionContext clone() {
        // 使用Gson序列化进行深拷贝
//        Gson gson = new Gson();
        Gson gson = new GsonBuilder().setExclusionStrategies(this).create();
        XDecisionContext newXDecisionContext = gson.fromJson(gson.toJson(this), XDecisionContext.class);
        //此处拷贝只深拷贝数据，不影响当前线程的数据，不然后续子线程的继承都发生的变化
        // threadLocal.set(copy);
        //该对象不需要深拷贝
//        copy.setPipelineMetaInfoContext(getPipelineMetaInfoContext());
        //该对象自定义序列化

        PipelineContext newPipelineContext = PipelineContextHolder.deepCopy();
        newXDecisionContext.setPipelineContext(newPipelineContext);

        return newXDecisionContext;
    }

    @Override
    public boolean shouldSkipField(FieldAttributes fieldAttributes) {
        return false;
    }

    @Override
    public boolean shouldSkipClass(Class<?> aClass) {

        if (aClass.getSimpleName().equals(com.baomidou.mybatisplus.core.mapper.Mapper.class.getSimpleName())) {
            return true;
        }
        if (aClass == MybatisMapperRegistry.class) {
            return true;
        }
        if (aClass == RiskDataApiAdapter.class) {
            return true;
        }
        return false;
    }

}
